package org.eclipse.gittab.ui.viewer;

import java.util.List;

import org.eclipse.gittab.fretboard.Fretboard;
import org.eclipse.gittab.fretboard.FretboardDesign;
import org.eclipse.gittab.fretboard.Fretboard.Configuration;
import org.eclipse.gittab.gitTabDsl.Fret;
import org.eclipse.gittab.gitTabDsl.Note;
import org.eclipse.gittab.gitTabDsl.Tuning;
import org.eclipse.gittab.util.GitTabUtil;
import org.eclipse.gittab.util.TuningMapper;
import org.eclipse.swt.widgets.Composite;

/**
 * Convenience class for using and configuring a {@link Fretboard}. </p> Uses
 * the "Builder" pattern for the configuration of the fretboard. See also
 * {@link ConfigBuilder}.
 * 
 * @author mtreitle
 * 
 */
public class FretboardViewer {

	/**
	 * It knows exactly how a {@link Configuration} must be filled.
	 * 
	 * @author mtreitle
	 * 
	 */
	public final class ConfigBuilder {

		protected final Configuration configuration = new Configuration();
		private final Fretboard fretboard;

		public ConfigBuilder(Fretboard fretboard) {
			this.fretboard = fretboard;
		}

		public ConfigBuilder tuneTo(Tuning tuning) {

			TuningMapper mapper = TuningMapper.TypeRegistry.CACHE;

			String[][] notes = TuningMapper.Util.mapToArray(mapper
					.getNotes(tuning));

			configuration.setNotes(notes);

			return this;
		}

		public ConfigBuilder lefty() {

			configuration.setLefty(true);
			return this;
		}

		public ConfigBuilder standard() {

			configuration.setLefty(false);
			return this;
		}

		public ConfigBuilder design(FretboardDesign design) {

			fretboard.setDesign(design);
			return this;
		}

		public ConfigBuilder defaultDesign() {

			fretboard.setDesign(fretboard.getDefaultDesign());
			return this;
		}

		public ConfigBuilder paintOn(Composite composite) {

			configuration.setComposite(composite);
			return this;
		}

		/**
		 * Paints the fretboard. May throw and {@link IllegalArgumentException}
		 * if configuration is not valid.
		 */
		public void apply() {

			fretboard.setConfiguration(configuration);

			fretboard.paint();
		}
	}

	private final Fretboard fretboard;

	private final ConfigBuilder configBuilder;

	public FretboardViewer(final Fretboard fretboard) {

		this.fretboard = fretboard;
		this.configBuilder = new ConfigBuilder(fretboard).standard()
				.defaultDesign();
	}

	public Fretboard getFretboard() {
		return fretboard;
	}

	public ConfigBuilder config() {
		return configBuilder;
	}

	public void play(List<Note> notes) {

		for (Note note : notes) {
			int string = GitTabUtil.guitarString2Int(note.getGitString());
			int fret = ((Fret) note.getNote()).getFret();
			fretboard.play(fret, string);
		}
	}

	public void clear(List<Note> notes) {

		for (Note note : notes) {
			int string = GitTabUtil.guitarString2Int(note.getGitString());
			int fret = ((Fret) note.getNote()).getFret();
			fretboard.clear(fret, string);
		}
	}

	public void clear() {
		fretboard.clearAll();
	}
}
